﻿using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace HeroldIT.Dnn.Modules.WebControls
{
    /// <summary>
    /// A control for dynamically creating a <see cref="System.Web.UI.WebControls.Button"/>
    /// or <see cref="LinkButton"/> control on a page.
    /// </summary>
    public class Button : Control, IButtonControl, INamingContainer
    {
        #region control fields

        private System.Web.UI.WebControls.Button button;
        private LinkButton linkButton;

        #endregion

        #region properties

        /// <summary>
        /// Gets or sets whether to display a <see cref="LinkButton"/> as opposed to a <see cref="System.Web.UI.WebControls.Button"/>.
        /// </summary>
        public bool UseLinkButton { get; set; }

        /// <summary>
        /// Gets or sets the url to an image to use for the <see cref="LinkButton"/>.
        /// </summary>
        public string ImageUrl { get; set; }

        /// <summary>
        /// Gets or sets the image's width.
        /// </summary>
        public Unit ImageWidth { get; set; }

        /// <summary>
        /// Gets or sets the image's height.
        /// </summary>
        public Unit ImageHeight { get; set; }

        /// <summary>
        /// Gets or sets the image's border width.
        /// </summary>
        public Unit ImageBorderWidth { get; set; }

        /// <summary>
        /// Gets or setswhether to display both image and text, or just the image, if one
        /// is specified in LinkButton mode.
        /// </summary>
        public bool DisplayImageAndText { get; set; }

        /// <summary>
        /// Gets or sets the css class to use for the button.
        /// </summary>
        public string CssClass
        {
            get
            {
                this.EnsureChildControls();
                return this.button.CssClass;
            }
            set
            {
                this.EnsureChildControls();
                this.button.CssClass = value;
                this.linkButton.CssClass = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether clicking the button causes page validation to occur.
        /// </summary>
        public bool CausesValidation
        {
            get
            {
                this.EnsureChildControls();
                return this.button.CausesValidation;
            }
            set 
            {
                this.EnsureChildControls();
                this.button.CausesValidation = value;
                this.linkButton.CausesValidation = value;
            }
        }

        /// <summary>
        /// Gets or sets an optional argument that is propagated to the <see cref="E:System.Web.UI.WebControls.IButtonControl.Command"/> event.
        /// </summary>
        public string CommandArgument
        {
            get
            {
                this.EnsureChildControls();
                return this.button.CommandArgument;
            }
            set
            {
                this.EnsureChildControls();
                this.button.CommandArgument = value;
                this.linkButton.CommandArgument = value;
            }
        }

        /// <summary>
        /// Gets or sets the command name that is propagated to the <see cref="E:System.Web.UI.WebControls.IButtonControl.Command"/> event.
        /// </summary>
        public string CommandName
        {
            get
            {
                this.EnsureChildControls();
                return this.button.CommandName;
            }
            set
            {
                this.EnsureChildControls();
                this.button.CommandName = value;
                this.linkButton.CommandName = value;
            }
        }

        /// <summary>
        /// Gets or sets javascript code to execute on the client, when the button is clicked.
        /// </summary>
        public string OnClientClick
        {
            get
            {
                this.EnsureChildControls();
                return this.button.OnClientClick;
            }
            set
            {
                this.EnsureChildControls();
                this.button.OnClientClick = value;
                this.linkButton.OnClientClick = value;
            }
        }

        /// <summary>
        /// Gets or sets the URL of the Web page to post to from the current page when the button control is clicked.
        /// </summary>
        public string PostBackUrl
        {
            get
            {
                this.EnsureChildControls();
                return this.button.PostBackUrl;
            }
            set
            {
                this.EnsureChildControls();
                this.button.PostBackUrl = value;
                this.linkButton.PostBackUrl = value;
            }
        }

        /// <summary>
        /// Gets or sets the text caption displayed for the button.
        /// </summary>
        public string Text
        {
            get
            {
                this.EnsureChildControls();
                return this.button.Text;
            }
            set
            {
                this.EnsureChildControls();
                this.button.Text = value;
                this.linkButton.Text = value;
            }
        }

        /// <summary>
        /// Gets or sets the name for the group of controls for which the button control causes validation when it posts back to the server.
        /// </summary>
        public string ValidationGroup
        {
            get
            {
                this.EnsureChildControls();
                return this.button.ValidationGroup;
            }
            set
            {
                this.EnsureChildControls();
                this.button.ValidationGroup = value;
                this.linkButton.ValidationGroup = value;
            }
        }

        #endregion

        #region events

        /// <summary>
        /// Fires, when the user clicks on the button.
        /// </summary>
        public event EventHandler Click;

        /// <summary>
        /// Fires the <see cref="Click"/> event.
        /// </summary>
        /// <param name="e">The arguments to pass to the event.</param>
        protected virtual void OnClick(EventArgs e)
        {
            EventHandler click = this.Click;
            if (click != null) click(this, e);
        }

        /// <summary>
        /// Fires, when a command is issued from the button.
        /// </summary>
        public event CommandEventHandler Command;

        /// <summary>
        /// Fires the <see cref="Command"/> event.
        /// </summary>
        /// <param name="e">The arguments to pass to the event.</param>
        protected virtual void OnCommand(CommandEventArgs e)
        {
            CommandEventHandler command = this.Command;
            if (command != null) command(this, e);
        }

        #endregion

        #region page lifecycle

        /// <summary>
        /// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering.
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            this.button = new System.Web.UI.WebControls.Button
                              {
                                  ID = "button"
                              };
            this.button.Click += (sender, args) => this.OnClick(args);
            this.button.Command += (sender, args) => this.OnCommand(args);
            this.Controls.Add(this.button);
            this.linkButton = new LinkButton
                                  {
                                      ID = "linkButton"
                                  };
            this.linkButton.Click += (sender, args) => this.OnClick(args);
            this.linkButton.Command += (sender, args) => this.OnCommand(args);
            this.Controls.Add(this.linkButton);            
        }

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.PreRender"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            this.button.Visible = !this.UseLinkButton;
            this.linkButton.Visible = this.UseLinkButton;
            if (this.UseLinkButton && !String.IsNullOrEmpty(this.ImageUrl))
            {
                string text = this.linkButton.Text;
                this.linkButton.Text = null;
                this.linkButton.Controls.Add(new Image
                                                 {
                                                     ID = "image",
                                                     AlternateText = text,
                                                     ToolTip = text,
                                                     BorderWidth = this.ImageBorderWidth,
                                                     ImageUrl = this.ImageUrl,
                                                     Width = this.ImageWidth,
                                                     Height = this.ImageHeight
                                                 });
                if (this.DisplayImageAndText)
                {
                    this.linkButton.Controls.Add(new Literal
                                          {
                                              Text = text
                                          });
                }
            }
        }

        #endregion
    }
}
